declare namespace test="http://www.gallio.org/";

declare variable $coverage-report := doc("Coverage.xml");
declare variable $test-report := doc("TestReport.xml");
declare variable $fxCop-report := doc("fxCop.xml")[doc-available("fxCop.xml")];
declare variable $styleCop-report := doc("StyleCop.xml")[doc-available("StyleCop.xml")];

declare variable $project-name := "DBLite";
declare variable $coverage-threshold := 1;

declare function local:coverage($method)
{
  let $count := count($method/code/pt)
  return if ($count = 0) then 1
         else count($method/code/pt[@visit!="0"]) div $count
};

declare function local:list-tests($tests)
{
  <h3>Failed Tests</h3>,
  <ul>{
  for $test in $tests
  let $name := string($test/test:testStep/@fullName)
  order by name
  return
    <li>{$name}</li>
  }</ul>
};

declare function local:list-coverage($coverage)
{
  <h3>Methods with insufficient coverage</h3>,
  <ul>{
  for $method in $coverage
  let $method-coverage := local:coverage($coverage)
  order by $method-coverage
  return
    <li>{
      let $sig := string($method/@sig)
      return
      (
          xs:normalizedString(substring-before($sig, "  ")),
          " ",
          <strong>{xs:string($method/parent::node()/@name), 
          ".",
          xs:string($method/@name)}</strong>,
          xs:normalizedString(substring-after($sig, "  "))
      )} ({round-half-to-even($method-coverage * 100, 2)}%)
    </li>
  }</ul>
};

declare function local:list-fxCop-issues($issues)
{
  <h3>Code analysis issues</h3>,
  <ul>{
  let $levels := ("CriticalError","Error","CriticalWarning","Warning")
  for $issue in $issues
  order by index-of($levels, string($issue/@Level)), string($issue/@Certainty) descending
  return
  <li>{string($issue/@Level)}: {string($issue)} ({string($issue/@Certainty)}% Certainty)</li>
  }</ul>
};

declare function local:list-styleCop-violations($violations)
{
  <h3>Source analysis issues</h3>,
  let $files := distinct-values($violations/@Source)
  for $file in $files
  return
  (
    <h4>{data($file)}</h4>,
    <ul>{
      for $violation in $violations[./@Source = $file]
      order by $violation/@LineNumber, $violation/@RuleId
      return
        <li>Line {data($violation/@LineNumber)}: {data($violation)}</li>
    }</ul>
  )
};

let $failed-tests := $test-report//test:testStepRun[test:result/test:outcome/@status="failed"][not(.//test:testStepRun)]
let $low-coverage := $coverage-report//method[local:coverage(.) < $coverage-threshold]
let $fxCop-issues := $fxCop-report//Issue
let $styleCop-violations := $styleCop-report//Violation
return
<html>
<head>
<title>{$project-name} Build Report</title>
</head>
<body>
<h1>{$project-name} Build Report</h1>
{
if ($failed-tests or $low-coverage or $fxCop-issues or $styleCop-violations)
then
  (<h2 style="background: red">Fail</h2>,
   local:list-tests($failed-tests)[$failed-tests],
   local:list-coverage($low-coverage)[$low-coverage],
   local:list-fxCop-issues($fxCop-issues)[$fxCop-issues],
   local:list-styleCop-violations($styleCop-violations)[$styleCop-violations])
else
  <h2 style="background: green">Success</h2>
}
</body>
</html>